MagnaMedia · AMIGA-Magazin · Installer-Scripts

Aktuelles Heft 5/97

Kurs:Installer-Skripts erstellen (Folge 3)

Out of the Box

Den Gesellenbrief in Sachen Installer haben wir nach den ersten beiden Folgen bereits in der Tasche. Ziel dieses Teils ist die Meisterpr�fung. Wir werden daher nun auch noch die letzten Geheimnisse der vielseitigen Skriptsprache ans Tageslicht bringen.

von Marcel Bennicke

Die meisten Ausgabefunktionen des Installers wandeln ihre Argumente automatisch in den jeweils erforderlichen Datentyp um, wie man es auch erwartet. Das ist zwar sehr praktisch, bringt aber wenig ein, da man keinerlei M�glichkeit hat, die Formatierung der Ausgabe zu beeinflussen. Deshalb kann der Installer auch mit vielen der in C �blichen Steuerzeichen (Stichwort: �printf�) umgehen. Um dieses Feature zu nutzen, klammert man an beliebiger Stelle einen String (der Steuerzeichen enth�lt) und z�hlt die einzuf�genden Daten danach auf. Einige Beispiele:

("Version %ld" #version)
("Sedezimal 43 = %lx" 43)
("CPU: %s, FPU %s" (database "CPU") (database "FPU"))
("Prozentangabe:%3ld%%" #x)
Intern wird die Formatierung mit der Exec-Funktion �RawDoFmt� abgewickelt. Alle dort bekannten Formatierunganweisungen sind damit auch im Installer nutzbar. Die wichtigsten sind �%ld� f�r Dezimalzahlen (das �l� steht f�r 32 Bit), �%lx� f�r sedezimale (auch hexadezimale) Ausgabe und �%s� f�r Strings. Ein einzelnes Prozentzeichen wird mit "%%� erzeugt.

Entlarvt: Manches System mu� sich mit unz�hligen Assigns herumschlagen. Der startup-Befehl f�gt sie in die user-startup ein.

Fehlerbehandlung

L�ngst nicht immer funktioniert alles so wie man es sich w�nscht. Speziell beim Installieren neuer Software kann doch einiges schiefgehen. Zum Beispiel neigen Datentr�ger irgendwann zur Ersch�pfung bzw. zu Fehlern und laut Murphy passiert das immer im ung�nstigsten Augenblick. Weitere Gr�nde k�nnen Speicherplatzmangel aber auch ein �Denkfehler� im Installerskript sein. W�hrend der erste Fall noch vermeidbar ist (und man sollte, bevor man irgendetwas kopiert, auch den verf�gbaren Platz �berpr�fen), sind die letztgenannten Fehlfunktionen eher von h�herer Gewalt verursacht. Wenn sie sich schon nicht ausschlie�en lassen, soll der Benutzer doch wenigstens �ber eventuelle Fehler informiert werden und das Installer-Skript mu� dem User die Chance erhalten, auf sie geeignet zu reagieren. Einen simplen Abfangmechanismus stellt die Anweisung �trap� zur Verf�gung. Sie arbeitet nach dem Prinzip des �RAISE XYZ IF ...�-Konstrukts in E, ist aber auch mit einem try-Block in C++ vergleichbar. Trap umrahmt eine Reihe von Anweisungen (oder das ganze Skript) und �berwacht sie automatisch auf bestimmte Fehler, welche durch Flags spezifiziert werden (s. Info-Kasten).

(trap \<Flags> \<Anweisungen>)

; trap-Demo; �1996 Marcel Bennicke

(onerror (message "Fehler konnte nicht abgefangen werden."
		  " Beende Skript!"))

(procedure P_Kopieren
  (copyfiles
    (prompt "Die Datei RAM:XYZ wird nun kopiert (existiert "
	    "gew�hnlich nicht, es kommt also zu einem DOS-Fehler)")
    (help "")
    (source "RAM:") (dest "RAM:t")
    (choices "XYZ") (confirm)
  )
)

; mit trap Fehler abfangen und Typ in #fehler speichern
(set #fehler
  (trap
    (
      (message "Die folgende Anweisung wird einen Fehler "
	       "provozieren. Sie k�nnen auch den Knopf "
	       "�Installation abbrechen� ausprobieren!")
      (P_Kopieren)
      (message "Hierhin gelangt man in Fehlerfall nicht")
)))

; war es wirklich ein Fehler?
(if #fehler
  (message "Ein Fehler ist aufgetreten: "
    (select #fehler "" "Benutzerabbruch" "Speicherplatzmangel"
		"Skript-Fehler" (cat "DOS-Fehler Nr. " @ioerr)
		"falsche Parameter")
  )
)

(message "Hier wird das Skript fortgesetzt. "
  "Anschlie�end das gleiche nocheinmal aber ohne trap")

(P_Kopieren)   ; provoziere Fehler

(message "Kopieren erfolgreich.")
Listing 1:Ausnahmebehandlung wie mit Amiga E -
einfacher geht es kaum

Tritt nun eine Fehlfunktion in einer der Anweisungen auf, wird das Skript nicht verlassen, sondern der Installer verzweigt zur n�chsten Anweisung hinter dem Trap-Block. Der Wert des Trap-Ausdrucks ist die Fehlernummer oder Null falls kein Fehler auftrat. Wie man �trap� sinnvoll nutzen kann, ist in Listing 1 zu sehen. Beim Ausprobieren dieser Funktion f�llt jedoch auf, da� sie in der aktuellen Fassung des Installers nicht nur auf die auftretenden Fehler reagierte, sondern stets auf alle Fehlfunktionen. Leider lassen sich mit �trap� nicht restlos alle Fehltritte bereinigen � einige f�hren unweigerlich zum Abbruch der Installationsprozedur. Damit man auch in diesem Fall wenigstens noch Aufr�umarbeiten durchf�hren kann, existiert die Anweisung �onerror�:

(onerror \<Anweisungen>)
Sie spezifiziert einen Block von Anweisungen, welche nach einem besonders schweren Fehler auszuf�hren sind. Anschlie�end verl��t der Installer die B�hne. Recht praktisch ist au�erdem, da� sich �onerror� auch mehrmals verwenden l��t, was kontextabh�ngige Fehlerbehandlung erm�glicht.

; Eingaben umlenken; �1996 Marcel Bennicke

; die einfache aber unsch�ne Methode
(run "format <>CON:0/10/400/50 DRIVE df0: NAME Leer"
  (prompt "Formatiere Diskette in Laufwerk DF0:\n")
  (help "") (confirm)
)

; so geht's besser
(textfile (dest "t:in") (append "\n"))
(set #name
  (askstring (prompt "Formatiere Diskette in DF0:. Bitte geben"
		     " Sie den Namen ein:")
	     (help "")
	     (default "Leer")
))

(run (cat "format <t:in DRIVE df0: NAME " #name)
  (prompt "Bitte Legen Sie eine Diskette in das Laufwerk DF0:")
  (help "") (confirm)
)
Listing 2: Ein Griff in die Trickkiste des AmigaDOS macht
den Formatbefehl wesentlich komfortabler

; startup-Demo; �1996 Marcel Bennicke

(startup "Startup-Demo"
  (prompt "F�ge einige Zeilen zur user-startup hinzu.")
  (help "")
  (command (cat "echo \"Test-Installation\"\n"
		"Assign XYZ: " @default-dest))
  (confirm)
)

(run "sys:utilities/Multiview S:user-startup"
  (prompt "user-startup wird angezeigt...")
  (help "") (confirm))
Listing 3: Der startup-Befehl f�gt Anweisungen in die
user-startup ein

Externe Programmteile

Die M�glichkeiten des Installers sind weit gef�chert. Trotzdem gibt es h�ufig Situationen, in denen man gern auf externe Programme oder ARexx-Skripts zur�ckgreifen m�chte, zum Beispiel, um Archive zu entpacken (entsprechende interne Funktionen sind zwar in Vorbereitung, arbeiten aber noch nicht korrekt). Drei einfache Befehle verleihen dem Installer in dieser Hinsicht besondere Flexibilit�t. Die Anweisung

(run \<Programm> [\<Argumente>])
startet ein externes AmigaDOS-Programm mit den entsprechenden Argumenten,

(execute \<Skript> [\<Argumente>])
f�hrt ein AmigaDOS-Skript aus und

(rexx \<ARexx-Programm> [\<Argumente>])
bringt ein ARexx-Programm zur Ausf�hrung (RexxMast mu� aktiv sein). Alle drei Anweisungen akzeptieren die gleichen Optionen, das Ergebnis der jeweiligen Operation wird vom Installer durchgereicht. Sekund�re Resultate werden in der Standardvariablen �@ioerr� gespeichert. So richtig haarig wird es aber erst, wenn ein AmigaDOS-Skript vom Installer zusammengebastelt werden mu� � die Konfiguration der Netzwerksoftware AmiTCP/IP erfolgt auf diese Weise. Auch an solche F�lle dachten die Entwickler und implementierten die Anweisung �textfile�. Mit ihrer Hilfe lassen sich beliebige Textdateien erstellen, indem man einzele Strings � oder gar andere Dateien � Schritt f�r Schritt zu einem Ganzen zusammenf�gt. Mit etwas Geschick erh�lt man so auch ARexx-Skripts, die der Installer selbst aufruft. Alles ist hier m�glich.

Doppelter Boden: Ein Netz, das fehlgeschlagene Aktionen auff�ngt, l��t sich mit der trap-Anweisung aufspannen

Ein anderes Problem k�nnen externe Programme sein, die ihre Eingaben in einem Shell-Fenster erwarten (zum Beispiel �Format� wartet auf Best�tigung durch <Return>). Ruft man ein solches Programm aus einem Installerskript auf, existiert selbstverst�ndlich keine Konsole, in die der Benutzer etwas eingeben k�nnte. Man kann nun Ein- und Ausgabekanal kurzerhand auf ein neues Fenster umlenken. Das hat allerdings den Nachteil, da� der Nutzer nun mit zwei Schnittstellen, dem Installer und der Konsole, hantieren mu�.

Eleganter ist es, alle Parameter direkt im Installer zu erfragen und anschlie�end nur den Eingabekanal durch eine zuvor angelegte Datei zu ersetzen (Listing 2).

Der Format-Befehl wird sich anschlie�end s�mtliche Eingaben aus der Datei �t:in� abholen. In diesem Fall enth�lt sie nur den Code f�r die <Return>-Taste. Nachteil dieser Methode: Abbruch durch <Ctrl-C>; ist nicht mehr m�glich. Ein sehr wichtiger Befehl ist �startup�. Er klinkt beliebige Programme in den Bootvorgang des Rechners ein, indem er die Datei �s:user-startup�, die das AmigaOS beim Hochfahren abarbeitet, um die entsprechenden Befehlszeilen erweitert. Das ist im �brigen der richtige Ort, um logische Zuweisungen f�r die eigene Applikation anzulegen.

Alle zu einem bestimmten Programm geh�renden Befehle umrahmt startup durch zwei Kommentare. Dadurch kann jeder Abschnitt in der user-startup einer Applikation zugeordnet werden. Installiert man nun dasselbe Programm nocheinmal (zum Beispiel nach einem Update), werden die alten Befehle automatisch durch neue ersetzt.

Symbolische Variablen

Das folgende Feature des Installers (seit V42.9) ist eine Besonderheit, die in dieser Form durch keinen Compiler realisiert werden kann. Mit Hilfe zweier Anweisungen, hat man die M�glichkeit, Variablen vollkommen dynamisch zu handhaben.

; Symbolische Variablen und Icons; �1996 Marcel Bennicke

(procedure P_Info #d (
  (iconinfo
    (dest #d) (getstack "#stack") (getposition "#x" "#y"))
  (message "\n\nDas Icon " #d ".info befindet sich an Position "
     #x "," #y " und ben�tigt " #stack " Bytes Stapelspeicher.")
))

(message "�ffnen Sie w�hrend das Skript abgearbeitet wird die "
	 "Schublade \"Sys:Prefs\" und beobachten, was passiert!")

(P_Info "sys:prefs/Font") ; Iconname ohne .info !

(working "Vertauche Position des Zeichensatz- und "
	 " Locale-Voreinstellers...")

(iconinfo (dest "sys:prefs/Font")   (getposition "#xf" "#yf"))
(iconinfo (dest "sys:prefs/Locale") (getposition "#xl" "#yl"))
(tooltype (dest "sys:prefs/Font")   (setposition #xl #yl))
(tooltype (dest "sys:prefs/Locale") (setposition #xf #yf))

(P_Info "sys:prefs/Font")
Listing 4: Auch mit Icons kann der Installer jonglieren.
Dieses Skript vertauscht die Position zweier Piktogramme.

Das bedeutet, Zugriffe auf deren Inhalte erfolgen nicht direkt unter Angabe eines Bezeichners im Quelltext, vielmehr ergeben sich Variablennamen aus dem aktuellen Inhalt von Strings. Dieses Verhalten ist dem von Zeigern in anderen Sprachen �hnlich. Die Anweisung

(symbolset \<Symbolname> \<Wert> ...)
implementiert die beschriebenen Features. Sie funktioniert bis auf die angesprochene Eigenheit exakt wie die normale set-Anweisung und dient dazu, Variablen Werte zuzuweisen. Der Bezeichner der betroffenen Variablen wird durch einen String oder beliebigen anderen Ausdruck (der eine Zeichenkette zum Ergebnis hat) charakterisiert.

(symbolset "#a" 1); =(set #a 1)
Zur Anweisung �symbolset� existiert selbstverst�ndlich auch ein Gegenst�ck �symbolval�, welche den Inhalt von Variablen ausliest. Als Argument erwartet die Funktion ebenfalls einen Ausdruck, der den gew�nschten Variablenbezeichner beschreibt:

(symbolval "#a") ; = 1

Handhabung von Piktogrammen

Der gute Stil
1 Der Installer wird durch eine eigene Sprache gesteuert. Inwieweit seine M�glichkeiten genutzt werden, h�ngt somit stark vom Layout des Skripts und damit von seinem Autor ab. Man sollte immer versuchen, s�mtliche Optionen korrekt zu implementieren. Eine �scheinbare Installation� etwa darf keinerlei dauerhafte Ver�nderungen im System vornehmen. Ebenso sollten einem Einsteiger keinerlei Informationen abverlangt, dem Experten jedoch ein gr��tm�gliches Ma� an Einflu�nahme gew�hrt werden.
2 Jede Frage an den Nutzer mu� durch einen Hilfetext begleitet werden.
3 Applikationen sollten ihre Dateien m�glichst zusammenhalten und nicht in die Systemordner verstreuen.
4 Zu einem guten Installerskript geh�rt auch immer das Gegenst�ck, eine Deinstallationsroutine, die Software wieder aus dem System entfernt.
5 Neuere Versionen von Libraries, Devices d�rfen nicht durch �ltere �berschrieben werden. Am besten man nutzt beim Kopieren dieser Dateien immer die Anweisung �copylib�.
6 Machen Sie bei der Frage nach dem Installationsverzeichnis deutlich, ob das Skript eine neue Schublade erzeugt.
Jeder der sich ein wenig mit AmigaOS auskennt, wei�, da� die vielen kleinen Piktogramme auf der Workbench mehr Informationen tragen als nur ihre eigenen Bilddaten. Je nach Typ enthalten sie den Namen eines Standardprogramms, eine Angabe �ber die erforderliche Gr��e des Stapelspeichers f�r ein Programm, ihre Position auf der Workbench und zahlreiche Konfigurationsdetails in Form von Tooltypes (Merkmale).

Vor allem bei Updates bereits installierter Applikationen kommt es darauf an, da� man diese Informationen nicht zerst�rt. Die Funktion �iconinfo� extrahiert alle ben�tigen Daten aus einem Piktogramm und speichert sie in separaten Variablen. Sie ist im �brigen zur Zeit die einzige Funktion, die das mit Hilfe symbolischer Variablen erledigt.

Von gr��erer Bedeutung, als das Extrahieren von Informationen aus einem Icon, ist der umgekehrte Weg. Viele Programmepakete nutzen gleich w�hrend der Installationsprozedur die Gelegenheit, ein paar Konfigurationsdaten -- etwa Pfade zu ben�tigten Dateien -- in den Tooltypes zu speichern. Mit Hilfe der Anweisung �tooltype� lassen sich Piktogrammerkmale ver�ndern, Stack sowie Standardprogramm zuordnen. Beispielsweise der Befehl

(tooltype
  (dest "ram:SuperPrg")
  (settooltype "FASTMODE")
  (settooltype "Level" "2")
  (settooltype "hungry" "")
  (setstack 20000)
)
l�scht im Piktogramm �RAM:SuperPrg.info� das Merkmal �FASTMODE�, erzeugt die zwei Merkmale �LEVEL� (mit dem Wert 2) sowie �HUNGRY� (ohne weitere Parameter) und setzt den Stack auf 20000 Bytes. Sogar die Positionsangaben eines Piktogramms k�nnen manipuliert werden. Es versteht sich von selbst, da� mit dieser Option sehr vorsichtig umzugehen ist. Sie dient vorrangig dazu, die von �iconinfo� gelieferten Koordinaten auf andere Piktogramme zu �bertragen. Listing 4 demonstriert, wie beide Anweisungen zusammenspielen.

Die Praxis

Zum Abschlu� unseres Kurses wollen wir Ihnen noch einige Kniffe vorstellen, wie man das eine oder andere Problem elegant l�st. Genau wie gew�hnliche Programme, wollen auch Installerskripts lokalisiert werden. Klar, man kann durchaus f�r jede Sprache ein eigenes Skript erstellen, aber sp�testens seit es die Locale-Library gibt, ist diese Methode nicht mehr zeitgem��. Am einfachsten lokalisiert man ein Skript, indem f�r s�mtliche Bildschirmtexte keinerlei feste Strings benutzt werden, sondern ausschlie�lich Variablen. Diese werden zu Beginn des Skripts entsprechend der eingestellten Sprache initialisiert (Standardvariable �@language�).

; Lokalisiertes Installerskript, �1996 Marcel Bennicke

; eine Sprache mu� ausgew�hlt werden
(set #loc 0)    ; Englisch ist Standard
(if (= @language "deutsch") (set #loc 1))

; Englische Strings ---------------------------------------
(if (= #loc 0)
(set
  #ask-where "Please select installation directory\n"
  #ask-age   "Please enter your age"
))

; Deutsche Strings ----------------------------------------
(if (= #loc 1)
(set
  #ask-where "Bitte w�hlen Sie das Installationsverzeichnis"
  #ask-age   "Bitte geben Sie ihr Alter ein"
))

; hier geht's los ----------------------------------------
(welcome)
(message "Dieses Skript spricht Deutsch und Englisch. "
	 "Starten Sie es mit verschiedenen Einstellungen "
	 "im Lokale-Voreinsteller!")

(set @default-dest
  (askdir (prompt #ask-where) (help @askdir-help)
	  (default @default-dest)))

(set #age (asknumber (prompt #ask-age) (help @asknumber-help)))
Listing 5: Selbst lokalisierte Skripts sind kein Problem

Es ist offensichtlich, da� sich so gleich mehrere Kataloge in ein Skript einbauen lassen und Erweiterungen leicht vorzunehmen sind. Listing 5 zeigt, wie es gemacht wird. Der Installer kennt nur zwei einfache Datentypen: Zahlen und Strings. Zusammen mit symbolischen Variablen und etwas Geschick lassen sich aber auch Arrays implementieren. Der Trick besteht lediglich darin, aus einer Grundzeichenkette (welche quasi den Namen des Arrays darstellt) und einem Index einen neuen Variablennamen zusammenzubasteln:

(set #index 0)
(symbolset ("#X%ld" #index) 4)
Man erzeugt also f�r jedes Element des Arrays letztlich eine eigene Variable (hier X0, X1...). M�chte man sp�ter den Inhalt auswerten, merkt man gar nicht mehr, wie die Variable erzeugt wurde:

(if (= #X0 4) ...) ; 1. Element
F�r Zugriffe mit variablem Index kann man den gleichen Trick wie oben anwenden:

(select ("X%ld" #i) "0" "1"...)
Damit sind wir am Ende unseres Kurses. S�mtliche Befehle und Anweisungen der zuletzt verf�gbaren Version wurden durchleutet, so da� Sie auf eine solide Grundlage zur�ckgreifen k�nnen.
lb
Anweisungen
Externe Programme
(execute \<Name> (prompt) (help) (confirm) (safe))
AmigaDOS-Skript ausf�hren

(rexx \<Name> (prompt) (help) (confirm) (safe))
ARexx-Skript ausf�hren

(run \<Name> (prompt) (help) (confirm) (safe))
AmigaDOS-Programm ausf�hren

(startup \<App-Name> (prompt) (help) (confirm) (command))
F�gt AmigaDOS-Befehle in die user-startup ein. Das Ergebnis des Ausdrucks �App-Name� erscheint als Kommentar �ber diesen Befehl command String, der die Befehle enth�lt (mehrere Zeilen durch �\n� trennen)

(textfile (prompt) (help) (dest) (append) (include) (confirm) (safe))
Erstellt eine (Text-)Datei mit dem Namen der in der Option �dest� angegeben wurde.
   append h�ngt einen String ans Dateiende
   include f�gt eine andere Datei ein

Kontrollanweisungen
(trap [\<Flags>] \<Anweisung>)
Tritt in einer der Anweisungen innerhalb des trap-Blocks ein Fehler auf, verzweigt der Installer an die n�chste, dem trap folgende Anweisung. Welche Fehler abgefangen werden, spezifizieren folgende Flags:
1Benutzerabbruch
2Speicherplatzmangel
3Fehler im Skript
4DOS-Fehler (Standardvariable @io-err)
5falsche Parameter bei Funktionsaufruf - der Wert eines trap-Ausdruckes ist die Fehlernummer oder Null.

(abort [\<Strings>])
Verl��t das Installerskript mit den angegebenen Meldungen, f�hrt aber im Gegensatz zu �exit� noch die durch �onerror� spezifizierten Anweisungen aus. Dient speziell dazu, aus einer Fehlersituation das Skript zu verlassen.

(onerror \<Anweisung>)
Im Fall, da� ein Fehler nicht abgefangen wurde, gelangen die Anweisungen des letzten onerror-Befehls zur Ausf�hrung, danach wird das Skript beendet.

(exit [\<Strings>])
Beendet die Ausf�hrung des Installerskripts, wird aber als Erfolg gewertet, d.h. die Meldung �Installation abgeschlossen� erscheint.

Verschiedene
(symbolset \<String> \<Wert> ...)
Belegt eine Variable, deren Name dem Inhalt des Strings (oder anderer Ausdruck mit einem String als Ergebnis) entspricht, mit einem Wert. Existiert diese Variable noch nicht, wird sie neu erzeugt.

(tooltype (prompt) (help) (dest) (settooltype) (setdefaulttool) (setstack) (noposition) (setposition) (confirm) (safe))
Ver�ndert Daten eines Piktogramms, dessen Name des in der Option �dest� zu �bergeben ist (ohne Endung �.info�)
    settooltype \<Merkmal> [\<Wert>]
Ver�ndert Merkmale. Ohne Angabe eines Wertes wird das Tooltype entfernt (beide Argumente sind Strings). Ein leeres Tooltype sieht so aus �(setdefaulttool "BIG "")�
setdefaulttool Name des Standardprogramms
setstack Stackgr��e
setposition \<x> \<y> (V42.12) Icons-Koordinaten auf WB

Funktionen
(iconinfo (prompt) (help) (dest) (gettooltype) (getstack) (getdefaulttool) (getposition) (confirm) (safe)) (V42.12)
Liefert Informationen �ber ein Piktogramm, dessen Name in �dest� (ohne �.info�) steht. Die Argumente der get... -Optionen sind symbolische Variablen (siehe auch �tooltype�).

(symbolval \) (V42.9)
Liefert den Inhalt der Variablen, dessen Name durch den �bergebenen Ausdruck bestimmt wird (s. a. �symbolset�).

(transcript \)
F�gt Strings in das Installationsprotokol ein


MagnaMedia Hauptseite

� Copyright by MagnaMedia Verlag AG, Haar bei M�nchen
Ver�ffentlichung und Vervielf�ltigung nur mit schriftlicher Genehmigung des Verlags


Kommentare, Fragen, Korrekturen und Kritik bitte an Webmaster AMIGA schicken.
Zuletzt aktualisiert am 28. April 1997.